/**
 * @file main.c
 * @brief Single-threaded server.
 * @author Leonardo Guilherme de Freitas
 * 
 * Implementação de um servidor single-threaded com suporte
 * a multiplos usuários.
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <limits.h>

#include "webserver.h"
#include "lib/server.h"
#include "lib/timeutil.h"
#include "lib/config.h"
#include <lib/pio.h>

char * serverpath;
int serverpathlen;
int interrupted = 0;
int mustreload = 0;
pio * io;

void intrhandler(int sig)
{
  interrupted = 1;
  printf("going down\n");
}

void reconfig(int sig)
{
  mustreload = 1;
  printf("Gotta reload\n");
  signal(SIGUSR2, reconfig);
}

void print_usage(const char *cmd)
{
  fprintf(stderr, "Uso:\n"
    "\t%s <arquivo de config> <tamanho do pool> [porta] [raiz] [velocidade]\n",
    cmd
  );
}


int main(int argc, char ** argv)
{
  int quit = 0, error = 0;
  size_t poolsize;
  long begin = 0, end = 0, delta = 0;
  char * filename = 0;
  
  serverconfig conf = {
    getpid(), /* id do processo usando essa config */
    9000, /* porta */
    1024000 /* velocidade */
  };
  
  memset(conf.root, 0, PATH_SIZE);
  
  server s;
  struct timespec start;
  
  if (argc < 3)
  {
    print_usage(argv[0]);
    exit(1);
  }

  // arquivo de config
  filename = argv[1];
  
  error = serverconfig_load(filename, &conf);
  if (error)
    fprintf(stderr, "Error loading %s\n", filename);
  
  conf.pid = getpid();
  if (conf.root[0] == '\0')
    getcwd(conf.root, PATH_SIZE);
  
  poolsize = atoi(argv[2]);
  
  if (argc > 3)
    conf.port = atoi(argv[3]);
  
  if (argc > 4)
  {
    if (realpath(argv[4], conf.root) == 0)
    {
      perror("Nao foi possivel acessar o path raiz");
      return 1;
    }
  }
  serverpath = conf.root;
  serverpathlen = strlen(serverpath) + 1;
  
  
  if (argc > 5)
    conf.speed = atoi(argv[5]);
  
  serverinit(&s, conf.port, conf.speed);

  printf("Canonical server path: %s\n", serverpath);
  printf("Speed control: %d bytes per second\n", conf.speed);
    
  s.update = server_threaded_update;
  s.quit = server_threaded_quit;
  
  /* cria o pio */
  io = piocreate(poolsize);
  
  signal(SIGINT, intrhandler);
  signal(SIGUSR2, reconfig);
  
  error = serverconfig_save(filename, &conf);
  if (error)
    printf("Error saving config %s\n", filename);
  
  // main loop
  while (!quit && !interrupted) {
    delta = (end-begin);
    if (s.clients == 0 || conf.speed == 0) /* sem cliente ainda ou sem bps */
      perai(10);
    else
      perai(1000000000L - delta);
    
    if (mustreload)
    {
      serverconfig_load(filename, &conf);
      serverpath = realpath(conf.root, conf.root);
      if (serverpath == 0)
      {
        perror("Nao foi possivel acessar o path raiz");
        break;
      }
      serverpathlen = strlen(serverpath) + 1;
      serverset(&s, conf.port, conf.speed);
      mustreload = 0;
    }
    
    begin = elapsed(&start);
    quit = serverupdate(&s);
    end = elapsed(&start);
  }
  piodestroy(io);
  serverdestroy(&s);

  return 0;
}